#include "Car.h"
#include "Tools.h"

CCScene* Car::scene()
{
	CCScene* sc = CCScene::create();
	Car* layer = Car::create();
	sc->addChild(layer);

	return sc; 
}

bool Car::init()
{
	BaseLayer::init();

	initGround();

	createCar();

	scheduleUpdate();
	setTouchEnabled(true);
	setTouchMode(kCCTouchesOneByOne);

	return true;
}

void Car::initGround()
{
	b2Vec2 vertices[8] = { b2Vec2(0, 0) };

	vertices[0] = Tools::convertTob2WorldSpace(ccp(0, winSize.height));
	vertices[1] = Tools::convertTob2WorldSpace(ccp(0, winSize.height/4));
	vertices[2] = Tools::convertTob2WorldSpace(ccp(winSize.width /4, winSize.height /4));
	vertices[3] = Tools::convertTob2WorldSpace(ccp(winSize.width * 5/12, winSize.height /8));
	vertices[4] = Tools::convertTob2WorldSpace(ccp(winSize.width * 7/12, winSize.height /8));
	vertices[5] = Tools::convertTob2WorldSpace(ccp(winSize.width * 3/4, winSize.height / 4));
	vertices[6] = Tools::convertTob2WorldSpace(ccp(winSize.width, winSize.height/4));
	vertices[7] = Tools::convertTob2WorldSpace(ccp(winSize.width, winSize.height));

	b2BodyDef bodyDef;
	bodyDef.type = b2_staticBody;
	bodyDef.position.Set(0, 0);

	b2Body* edgeBody = m_world->CreateBody(&bodyDef);

	for (int i = 0; i < 7; i++) {
		b2EdgeShape edgeShape;
		edgeShape.Set(vertices[i], vertices[i + 1]);
		edgeBody->CreateFixture(&edgeShape, 0.0f);
	}

	m_groundBody = edgeBody;
}

void Car::createCar()
{
	b2PolygonShape chassis;
	b2Vec2 vertices[8];
	vertices[0].Set(-1.5f, -0.5f);
	vertices[1].Set(1.5f, -0.5f);
	vertices[2].Set(1.5f, 0.0f);
	vertices[3].Set(0.0f, 0.9f);
	vertices[4].Set(-1.15f, 0.9f);
	vertices[5].Set(-1.5f, 0.2f);
	chassis.Set(vertices, 6);

	b2CircleShape circle;
	circle.m_radius = 0.4f;

	b2Vec2 startVec = Tools::convertTob2WorldSpace(ccp(winSize.width/8, winSize.height/4));

	b2BodyDef bodyDef;
	bodyDef.type = b2_dynamicBody;
	bodyDef.position.Set(startVec.x, startVec.y + 1.0f);
	m_car = m_world->CreateBody(&bodyDef);
	m_car->CreateFixture(&chassis, 1.0f);

	b2FixtureDef fd;
	fd.shape = &circle;
	fd.density = 1.0f;
	fd.friction = 1.0f;

	bodyDef.position.Set(startVec.x - 1.0f, startVec.y + 0.35f);
	m_wheel1 = m_world->CreateBody(&bodyDef);
	m_wheel1->CreateFixture(&fd);

	bodyDef.position.Set(startVec.x + 1.0f, startVec.y + 0.4f);
	m_wheel2 = m_world->CreateBody(&bodyDef);
	m_wheel2->CreateFixture(&fd);

	b2WheelJointDef jd;
	b2Vec2 axis(0.0f, 1.0f);

	jd.Initialize(m_car, m_wheel1, m_wheel1->GetPosition(), axis);
	jd.motorSpeed = -10.0f;
	jd.maxMotorTorque = 20.0f;
	jd.enableMotor = true;
	jd.frequencyHz = m_hz;
	jd.dampingRatio = m_zeta;
	m_spring1 = (b2WheelJoint*)m_world->CreateJoint(&jd);

	jd.Initialize(m_car, m_wheel2, m_wheel2->GetPosition(), axis);
	jd.motorSpeed = 0.0f;
	jd.maxMotorTorque = 20.0f;
	jd.enableMotor = false;
	jd.frequencyHz = m_hz;
	jd.dampingRatio = m_zeta;
	m_spring2 = (b2WheelJoint*)m_world->CreateJoint(&jd);
}

void Car::update(float delta)
{
	m_world->Step(delta, 8, 1);
}

bool Car::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
	const CCPoint ptTouch = pTouch->getLocation();
	b2Vec2 bodyVec = Tools::convertTob2WorldSpace(ptTouch);

	for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext()) {
		for (b2Fixture* fix = b->GetFixtureList(); fix; fix = fix->GetNext()) {
			if (fix->TestPoint(bodyVec)) {
				b2MouseJointDef jointDef;
				jointDef.bodyA = m_groundBody;
				jointDef.bodyB = b;
				jointDef.target = bodyVec;
				jointDef.maxForce = 1000 * b->GetMass();
				b->SetAwake(true);
				m_mouseJoint = (b2MouseJoint*)m_world->CreateJoint(&jointDef);
			}
		}
	}

	return true;
}

void Car::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
	if (!m_mouseJoint) return;

	const CCPoint ptTouch = pTouch->getLocation();
	m_mouseJoint->SetTarget(Tools::convertTob2WorldSpace(ptTouch));
}

void Car::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
	if (m_mouseJoint) {
		m_world->DestroyJoint(m_mouseJoint);
		m_mouseJoint = NULL;
	}
}